#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import subprocess
import os
import re
import shutil
import tempfile
import time
# 添加以下导入
import platform

from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QPushButton, QLabel, QListWidget, QTextEdit, QLineEdit, 
                             QMessageBox, QDialog, QFrame, QGridLayout, QSizePolicy, QListWidgetItem)
from PyQt5.QtCore import Qt, pyqtSignal, QObject, QThread, QTimer
from PyQt5.QtGui import QFont, QColor, QIcon
# 添加以下导入
from PyQt5.QtWidgets import QStyleFactory

# 确保使用 PyQt5 而不是其他 GUI 后端
os.environ['QT_QPA_PLATFORM'] = 'xcb'
# 禁用可能引起问题的 GUI 后端
os.environ['MPLBACKEND'] = 'Qt5Agg' if 'matplotlib' in sys.modules else ''

# 版本信息
KM_VERSION = "1.2.3-12"

class PackageManager:
    """包管理器类"""
    def __init__(self):
        self.package_manager = self._detect_package_manager()
        
    def _detect_package_manager(self):
        """通过检测可用的包管理器来确定系统类型"""
        # 检测 apt (Debian/Ubuntu 系列)
        if shutil.which('apt-get'):
            return 'apt'
        else:
            raise RuntimeError("不支持的包管理器，仅支持Ubuntu/Debian系统")
            
    def get_package_names(self, kernel_version, action='install'):
        """根据包管理器和操作类型生成相关的包名列表"""
        packages = []
        
        if self.package_manager == 'apt':
            if action == 'install':
                packages.extend([
                    f'linux-image-{kernel_version}',
                    f'linux-headers-{kernel_version}',
                ])
            else:  # remove
                packages.extend([
                    f'linux-image-{kernel_version}',
                    f'linux-headers-{kernel_version}',
                ])
        else:
            raise RuntimeError(f"不支持的包管理器: {self.package_manager}")
            
        return packages
    
    def install_packages(self, package_names, log_window=None):
        """安装多个包"""
        self._install_package_list(package_names, log_window)
        return package_names
    
    def remove_packages(self, package_names, log_window=None):
        """移除多个包"""
        self._remove_package_list(package_names, log_window)
    
    def _install_package_list(self, package_names, log_window=None):
        """安装包列表"""
        try:
            if self.package_manager == 'apt':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行安装命令...")
                        result = subprocess.Popen(['pkexec', 'apt-get', 'install', '-y'] + package_names, 
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行安装命令...")
                            result = subprocess.Popen(['sudo', 'apt-get', 'install', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法安装包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行安装命令...")
                    result = subprocess.Popen(['apt-get', 'install', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
        except Exception as e:
            raise RuntimeError(f"安装包失败: {str(e)}")
    
    def _remove_package_list(self, package_names, log_window=None):
        """移除包列表"""
        try:
            if self.package_manager == 'apt':
                if os.geteuid() != 0:
                    try:
                        if log_window:
                            log_window.add_log("使用 pkexec 执行移除命令...")
                        result = subprocess.Popen(['pkexec', 'apt-get', 'remove', '-y'] + package_names, 
                                                stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                universal_newlines=True)
                        # 实时读取输出
                        for line in iter(result.stdout.readline, ''):
                            if log_window:
                                log_window.add_log(line.rstrip())
                        for line in iter(result.stderr.readline, ''):
                            if log_window:
                                log_window.add_log("错误: " + line.rstrip())
                        result.wait()
                        if result.returncode != 0:
                            raise subprocess.CalledProcessError(result.returncode, result.args)
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            if log_window:
                                log_window.add_log("使用 sudo 执行移除命令...")
                            result = subprocess.Popen(['sudo', 'apt-get', 'remove', '-y'] + package_names,
                                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                                    universal_newlines=True)
                            # 实时读取输出
                            for line in iter(result.stdout.readline, ''):
                                if log_window:
                                    log_window.add_log(line.rstrip())
                            for line in iter(result.stderr.readline, ''):
                                if log_window:
                                    log_window.add_log("错误: " + line.rstrip())
                            result.wait()
                            if result.returncode != 0:
                                raise subprocess.CalledProcessError(result.returncode, result.args)
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            raise PermissionError("无法移除包")
                else:
                    if log_window:
                        log_window.add_log("以 root 权限执行移除命令...")
                    result = subprocess.Popen(['apt-get', 'remove', '-y'] + package_names, 
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
                                            universal_newlines=True)
                    # 实时读取输出
                    for line in iter(result.stdout.readline, ''):
                        if log_window:
                            log_window.add_log(line.rstrip())
                    for line in iter(result.stderr.readline, ''):
                        if log_window:
                            log_window.add_log("错误: " + line.rstrip())
                    result.wait()
                    if result.returncode != 0:
                        raise subprocess.CalledProcessError(result.returncode, result.args)
                        
        except Exception as e:
            raise RuntimeError(f"移除包失败: {str(e)}")


class InstallRecordManager:
    RECORD_FILE = ".config/kernel-management/install-records.log"
    
    @classmethod
    def add_record(cls, kernel_version, packages):
        """添加安装记录"""
        try:
            os.makedirs(os.path.dirname(cls.RECORD_FILE), exist_ok=True)
            with open(cls.RECORD_FILE, 'a') as f:
                f.write(f"{kernel_version}:{','.join(packages)}\n")
        except PermissionError:
            print(f"权限不足，无法写入安装记录文件: {cls.RECORD_FILE}")
        except Exception as e:
            print(f"写入安装记录失败: {e}")
    
    @classmethod
    def remove_record(cls, kernel_version):
        """移除安装记录"""
        try:
            if not os.path.exists(cls.RECORD_FILE):
                return
            
            lines = []
            with open(cls.RECORD_FILE, 'r') as f:
                lines = f.readlines()
            
            with open(cls.RECORD_FILE, 'w') as f:
                for line in lines:
                    if not line.startswith(f"{kernel_version}:"):
                        f.write(line)
        except Exception:
            pass  # 忽略记录失败
    

    @classmethod
    def load_records(cls):
        """加载安装记录"""
        records = {}
        try:
            if os.path.exists(cls.RECORD_FILE):
                with open(cls.RECORD_FILE, 'r') as f:
                    for line in f:
                        if ':' in line:
                            kernel_version, packages = line.strip().split(':', 1)
                            records[kernel_version] = packages.split(',')
        except Exception:
            pass  # 忽略记录失败
        return records

class DefaultBootManager:
    """默认启动管理器"""
    DEFAULT_BOOT_FILE = ".config/kernel-management/default-kernel.log"
    NEXT_BOOT_FILE = "/tmp/kernel-management/next-boot-kernel.log"

    
    @classmethod
    def save_default_boot(cls, kernel_version):
        """保存默认启动内核记录"""
        try:
            os.makedirs(os.path.dirname(cls.DEFAULT_BOOT_FILE), exist_ok=True)
            with open(cls.DEFAULT_BOOT_FILE, 'w') as f:
                f.write(kernel_version)
        except Exception:
            pass  # 忽略记录失败
    
    @classmethod
    def save_next_boot(cls, kernel_version):
        """保存下次启动内核记录"""
        try:
            os.makedirs(os.path.dirname(cls.NEXT_BOOT_FILE), exist_ok=True)
            with open(cls.NEXT_BOOT_FILE, 'w') as f:
                f.write(kernel_version)
        except Exception:
            pass  # 忽略记录失败
    
    @classmethod
    def load_default_boot(cls):
        """加载默认启动内核记录"""
        try:
            if os.path.exists(cls.DEFAULT_BOOT_FILE):
                with open(cls.DEFAULT_BOOT_FILE, 'r') as f:
                    return f.read().strip()
        except Exception:
            pass
        return None
    
    @classmethod
    def load_next_boot(cls):
        """加载下次启动内核记录"""
        try:
            if os.path.exists(cls.NEXT_BOOT_FILE):
                with open(cls.NEXT_BOOT_FILE, 'r') as f:
                    return f.read().strip()
        except Exception:
            pass
        return None

class BootManager:
    GRUB_CONFIG_PATHS = [
        "/boot/grub/grub.cfg",
        "/boot/grub2/grub.cfg"
    ]
    
    GRUB_DEFAULT_PATH = "/etc/default/grub"
    GRUB_ENV_PATH = "/boot/grub/grubenv"
    
    def __init__(self, gui_instance):
        self.gui_instance = gui_instance  # 保存GUI实例的引用
        self.grub_cfg_path = self._detect_grub_config()
        
    def _detect_grub_config(self):
        """检测GRUB配置文件路径"""
        for path in self.GRUB_CONFIG_PATHS:
            if os.path.exists(path):
                return path
        return self.GRUB_CONFIG_PATHS[0]  # 默认返回第一个
    
    def get_boot_entries(self):
        """获取启动条目列表"""
        return self.get_grub_entries()
    
    def get_grub_entries(self):
        """获取GRUB启动条目"""
        entries = []
        
        try:
            # 读取GRUB配置文件
            if os.geteuid() != 0:
                try:
                    result = subprocess.run(['pkexec', 'cat', self.grub_cfg_path], 
                                        capture_output=True, text=True, check=True)
                    content = result.stdout
                except (subprocess.CalledProcessError, FileNotFoundError):
                    try:
                        result = subprocess.run(['sudo', 'cat', self.grub_cfg_path], 
                                            capture_output=True, text=True, check=True)
                        content = result.stdout
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        raise PermissionError("无法读取GRUB配置文件")
            else:
                with open(self.grub_cfg_path, 'r') as f:
                    content = f.read()
            
            # 解析结构
            current_submenus = []  # 跟踪当前的submenu路径
            lines = content.split('\n')
            
            i = 0
            while i < len(lines):
                line = lines[i]
                stripped_line = line.strip()
                
                # 跳过空行
                if not stripped_line:
                    i += 1
                    continue
                
                # 检查submenu
                submenu_match = re.match(r"submenu\s+'([^']+)'", stripped_line)
                if submenu_match:
                    submenu_title = submenu_match.group(1)
                    # 检查是否在行首
                    is_at_line_start = line == stripped_line
                    if is_at_line_start:
                        # 顶级submenu，重置路径
                        current_submenus = [submenu_title]
                    else:
                        # 嵌套submenu，添加到当前路径
                        # 简化处理：我们假设正常的GRUB结构
                        if current_submenus:
                            # 保持当前路径不变，因为我们主要关心menuentry的位置
                            pass
                    i += 1
                    continue
                
                # 检查menuentry
                menuentry_match = re.match(r"menuentry\s+'([^']+)'", stripped_line)
                if menuentry_match:
                    title = menuentry_match.group(1)
                    # 查找内核版本
                    version = None
                    j = i + 1
                    while j < len(lines) and lines[j].strip() != '}':
                        linux_match = re.search(r'linux.*?/boot/vmlinuz-(\S+)', lines[j])
                        if linux_match:
                            version = linux_match.group(1)
                            break
                        j += 1
                    
                    # 如果通过linux命令未找到版本，尝试从标题中提取
                    if not version:
                        version = self._extract_kernel_version_from_title(title)
                    
                    # 判断是否为子菜单项：检查menuentry是否在行首
                    is_at_line_start = line == stripped_line
                    is_submenu_entry = not is_at_line_start  # 不在行首的就是子菜单项
                    
                    # 构建完整路径
                    if is_submenu_entry and current_submenus:
                        # 如果是子菜单项且有submenu上下文，则构建完整路径
                        full_path = ">".join(current_submenus + [title])
                    else:
                        # 否则只使用标题
                        full_path = title
                        # 如果是顶级menuentry，重置submenu上下文
                        if is_at_line_start:
                            current_submenus = []
                    
                    entries.append({
                        'title': title,
                        'version': version,
                        'identifier': full_path,
                        'is_submenu_entry': is_submenu_entry
                    })
                
                i += 1
                        
        except Exception as e:
            print(f"解析GRUB条目失败: {e}")
            raise RuntimeError(f"无法解析GRUB启动条目: {e}")
        
        # 打印解析结果到日志（如果在设置默认内核的上下文中）
        try:
            # 尝试获取当前操作上下文
            import traceback
            stack = traceback.extract_stack()
            in_default_setting = any('set_default_kernel_with_recommended_method' in frame.name for frame in stack)
            
            if in_default_setting and hasattr(self, 'gui_instance') and self.gui_instance:
                # 在设置默认内核时，输出解析结果到日志
                try:
                    log_window = getattr(self.gui_instance, '_current_log_window', None)
                    if log_window:
                        log_window.add_log("\n=== GRUB条目解析结果 ===")
                        for i, entry in enumerate(entries):
                            log_window.add_log(f"{i+1:2d}. 标题: {entry['title']}")
                            log_window.add_log(f"     版本: {entry['version'] or 'N/A'}")
                            log_window.add_log(f"     标识符: {entry['identifier']}")
                            log_window.add_log(f"     子菜单项: {'是' if entry['is_submenu_entry'] else '否'}")
                            log_window.add_log("")
                except:
                    pass  # 忽略日志输出错误
        except:
            pass  # 忽略上下文检查错误
        
        return entries

    def _extract_kernel_version_from_title(self, title):
        """
        从标题中提取内核版本信息
        特别针对深度操作系统等自定义格式的GRUB菜单
        """
        # 常见的内核版本模式
        patterns = [
            r'linux\s+([\d\.\-\w]+)',  # 匹配 "linux X.X.X-..." 格式
            r'linux\s+version\s+([\d\.\-\w]+)',  # 匹配 "linux version X.X.X-..." 格式
            r'kernel\s+([\d\.\-\w]+)',  # 匹配 "kernel X.X.X-..." 格式
            r'version\s+([\d\.\-\w]+)',  # 匹配 "version X.X.X-..." 格式
            r'(\d+\.\d+\.\d+[-\w]*)',  # 匹配纯版本号格式如 "X.X.X-..."
            r'Linux\s+([\d\.\-\w]+)',  # 匹配 "Linux X.X.X-..." 格式
            r'with\s+Linux\s+([\d\.\-\w]+)',  # 匹配 "with Linux X.X.X-..." 格式
        ]
        
        # 针对深度操作系统的特殊处理
        # 匹配 "Linux X.X.X-amd64-desktop-rolling" 格式
        deepin_pattern = r'Linux\s+(\d+\.\d+\.\d+[-\w]*)'
        match = re.search(deepin_pattern, title)
        if match:
            return match.group(1)
        
        # 尝试其他通用模式
        for pattern in patterns:
            match = re.search(pattern, title, re.IGNORECASE)
            if match:
                return match.group(1)
        
        # 如果以上都没匹配到，返回None
        return None

    
    def set_default_entry(self, identifier):
        """设置默认启动条目"""
        self.set_default_kernel_with_recommended_method(identifier, permanent=True)
    
    def set_next_boot_entry(self, identifier):
        """设置下次启动条目"""
        self.set_default_kernel_with_recommended_method(identifier, permanent=False)


    def set_default_kernel_with_recommended_method(self, identifier=None, permanent=True):
        """
        使用GRUB推荐方式设置默认启动内核
        现在默认使用GRUB 2.0+的方式
        """
        log_window = None  # 初始化为 None
        action_type = "永久" if permanent else "临时"  # 初始化 action_type
        
        try:
            # 获取选中的内核条目
            items = self.gui_instance.install_listbox.selectedItems()
            if not items:
                self.gui_instance.show_message("提示", "请先选择一个内核", 'warning')
                return
            elif "✓ " not in items[0].text():  # 修正检查方式
                # 未安装提示先安装
                self.gui_instance.show_message("提示", "选择的内核未安装，请先安装后再试！")
                return

            item = items[0]
            # 提取内核名称（去除标记符号）
            kernel_name = item.text().replace("✓ ", "").replace("○ ", "").split(" ")[0]
            
            # 根据不同包管理器提取版本号
            if kernel_name.startswith('linux-image-'):
                kernel_version = kernel_name.replace('linux-image-', '')
            elif kernel_name.startswith('kernel-'):
                kernel_version = kernel_name.replace('kernel-', '')
            else:
                kernel_version = kernel_name.replace('linux-', '')
            
            # 确认设置
            if not self.gui_instance.show_message("确认设置", f"确定要将 {kernel_name} 设置为{action_type}默认启动内核吗？\n将使用GRUB推荐方式设置。", 'question'):
                return
                
            # 创建日志窗口
            log_window = LogWindow(self.gui_instance, f"设置{action_type}默认内核 {kernel_name} 的日志")
            log_window.add_log(f"开始设置{action_type}默认启动内核: {kernel_name}")
            log_window.add_log(f"内核版本: {kernel_version}")
            
            # 保存日志窗口引用，供其他方法使用
            self.gui_instance._current_log_window = log_window
            
            self.gui_instance.install_status_label.setText(f"正在设置 {kernel_name} 为{action_type}默认启动内核...")
            QApplication.processEvents()
            
            # 获取GRUB版本
            grub_version = self.get_grub_version()
            log_window.add_log(f"检测到GRUB版本: {grub_version}")
            
            # 查找目标内核条目
            target_entry = self.find_grub_entry_for_kernel(kernel_version)
            if not target_entry:
                raise RuntimeError(f"在GRUB菜单中找不到内核 {kernel_version} 的条目")
            
            log_window.add_log(f"找到目标条目: {target_entry['title']} (版本: {target_entry['version']})")
            
            # 现在默认使用GRUB 2.0+的方式设置
            menu_path = self.construct_grub_200_plus_menu_path(kernel_version)
            log_window.add_log(f"使用GRUB 2.0+推荐方式设置默认启动项: {menu_path}")
            
            # 设置默认启动项
            if permanent:
                self._update_grub_default_config(f'GRUB_DEFAULT="{menu_path}"')
                log_window.add_log("已永久设置GRUB默认启动项")
                # 记录到本地文件
                DefaultBootManager.save_default_boot(kernel_version)
                log_window.add_log("已记录为默认启动内核")
                # 更新GRUB配置
                self.update_grub_config()
                log_window.add_log("已更新GRUB配置")
            else:
                self._set_next_boot_entry(menu_path)
                log_window.add_log("已设置下次启动项")
                # 记录到本地文件
                DefaultBootManager.save_next_boot(kernel_version)
                log_window.add_log("已记录为下次启动内核")
            
            log_window.add_log(f"{action_type}默认启动条目设置完成")
            log_window.add_log(f"已将 {kernel_name} 设置为{action_type}默认启动内核（使用GRUB推荐方式）")
            
            # 清理日志窗口引用
            if hasattr(self.gui_instance, '_current_log_window'):
                delattr(self.gui_instance, '_current_log_window')
            
            # 这里不直接调用 show_message，而是返回一个结果给 KernelManagementGUI 处理
            return {
                "success": True,
                "message": f"已将 {kernel_name} 设置为{action_type}默认启动内核",
                "title": "成功"
            }
            
        except Exception as e:
            # 只有在 log_window 已经成功初始化的情况下才使用它
            if log_window is not None:
                log_window.add_log(f"设置{action_type}默认启动内核失败: {str(e)}")
                # 清理日志窗口引用
                if hasattr(self.gui_instance, '_current_log_window'):
                    delattr(self.gui_instance, '_current_log_window')
            # 返回错误信息给 KernelManagementGUI 处理
            return {
                "success": False,
                "message": f"设置{action_type}默认启动内核失败: {str(e)}",
                "title": "错误"
            }
        else:
            self.gui_instance.install_status_label.setText("设置完成")
            QApplication.processEvents()  # 确保状态更新立即显示

    def get_grub_version(self):
        """获取GRUB版本"""
        try:
            result = subprocess.run(['grub-install', '--version'], 
                                  capture_output=True, text=True, check=True)
            version_line = result.stdout.strip()
            # 提取版本号 (格式: "grub-install (GRUB) 2.06")
            import re
            match = re.search(r'GRUB\)\s+([\d.]+)', version_line)
            if match:
                return match.group(1)
        except (subprocess.CalledProcessError, FileNotFoundError):
            pass
        return None

    def is_grub_200_or_later(self, version_str):
        """判断GRUB版本是否为2.00或更高"""
        # 修改为始终返回True，即默认使用GRUB 2.0+的方式
        return True
        
    
    def find_grub_entry_for_kernel(self, target_kernel_version):
        """查找GRUB中对应内核的条目"""
        try:
            # 获取GRUB条目
            entries = self.get_grub_entries()
            if not entries:
                return None
            
            # 查找目标内核条目（优先选择非恢复模式的条目）
            target_entry = None
            for entry in entries:
                # 首先尝试通过版本号匹配
                if (entry['version'] and 
                    (target_kernel_version == entry['version'] or 
                    target_kernel_version in entry['version'] or 
                    entry['version'] in target_kernel_version) and
                    'recovery' not in entry['title'].lower() and 
                    '恢复' not in entry['title']):
                    target_entry = entry
                    break
                
                # 如果没有通过版本号匹配，则尝试通过标题匹配
                elif (target_kernel_version in entry['title'] and
                    'recovery' not in entry['title'].lower() and
                    '恢复' not in entry['title']):
                    target_entry = entry
                    break
            
            # 如果没找到非恢复模式条目，则查找任何匹配的条目（包括恢复模式）
            if not target_entry:
                for entry in entries:
                    if (entry['version'] and 
                        (target_kernel_version == entry['version'] or 
                        target_kernel_version in entry['version'] or 
                        entry['version'] in target_kernel_version)):
                        target_entry = entry
                        break
                    elif target_kernel_version in entry['title']:
                        target_entry = entry
                        break
            
            return target_entry
        except Exception as e:
            print(f"查找GRUB条目失败: {e}")
            return None

    def construct_grub_200_plus_menu_path(self, kernel_version):
        """
        为深度系统优化GRUB菜单路径构建
        """
        try:
            # 获取GRUB条目
            entries = self.get_grub_entries()
            
            # 针对深度系统的特殊处理
            target_entry = None
            
            # 优先查找匹配的高级选项菜单项
            for entry in entries:
                if (entry['version'] and 
                    (kernel_version == entry['version'] or 
                    kernel_version in entry['version']) and
                    'recovery' not in entry['title'].lower() and
                    '恢复' not in entry['title'] and
                    entry['is_submenu_entry']):
                    target_entry = entry
                    break
            
            # 如果没找到，尝试查找任何匹配项
            if not target_entry:
                for entry in entries:
                    if (entry['version'] and 
                        (kernel_version == entry['version'] or 
                        kernel_version in entry['version']) and
                        'recovery' not in entry['title'].lower() and
                        '恢复' not in entry['title']):
                        target_entry = entry
                        break
            
            if target_entry and 'identifier' in target_entry:
                return target_entry['identifier']
                
            raise RuntimeError(f"找不到内核版本 {kernel_version} 的GRUB条目")
                
        except Exception as e:
            raise RuntimeError(f"构建GRUB菜单路径失败: {e}")


    def get_root_uuid(self):
        """获取根分区UUID"""
        try:
            # 尝试多种方式获取根分区UUID
            commands = [
                ['lsblk', '-f', '-o', 'UUID,MOUNTPOINT'],
                ['sudo', 'lsblk', '-f', '-o', 'UUID,MOUNTPOINT'],
                ['pkexec', 'lsblk', '-f', '-o', 'UUID,MOUNTPOINT']
            ]
            
            for cmd in commands:
                try:
                    result = subprocess.run(cmd, capture_output=True, text=True, check=True)
                    lines = result.stdout.strip().split('\n')
                    for line in lines[1:]:  # 跳过标题行
                        parts = line.split()
                        if len(parts) >= 2 and '/' in parts[-1] and parts[-1].strip() == '/':
                            return parts[0]  # 返回根分区UUID
                except (subprocess.CalledProcessError, FileNotFoundError):
                    continue
                    
            # 如果上面的方法失败，尝试使用blkid
            try:
                result = subprocess.run(['blkid'], capture_output=True, text=True, check=True)
                # 查找包含"/"的行（根分区）
                import re
                for line in result.stdout.split('\n'):
                    if 'UUID=' in line and '/dev/' in line:
                        uuid_match = re.search(r'UUID="([^"]+)"', line)
                        if uuid_match and '/dev/' in line:
                            # 进一步确认是否为根分区
                            if 'TYPE="ext"' in line or 'TYPE="btrfs"' in line or 'TYPE="xfs"' in line:
                                return uuid_match.group(1)
            except (subprocess.CalledProcessError, FileNotFoundError):
                pass
                
        except Exception as e:
            print(f"获取根分区UUID失败: {e}")
        
        return None

    def _update_grub_default_config(self, new_default_line):
        """更新GRUB默认配置文件 - 安全版本"""
        try:
            # 验证输入
            if not self._is_valid_grub_default(new_default_line):
                raise ValueError("无效的GRUB默认配置")
            
            # 使用更安全的临时文件处理
            with tempfile.NamedTemporaryFile(mode='w', delete=False, prefix='grub_default_') as tmp_file:
                # 读取原配置文件
                original_lines = []
                if os.path.exists(self.GRUB_DEFAULT_PATH):
                    with open(self.GRUB_DEFAULT_PATH, 'r') as f:
                        original_lines = f.readlines()
                
                # 写入修改后的配置
                grub_default_found = False
                for line in original_lines:
                    if line.startswith('GRUB_DEFAULT='):
                        tmp_file.write(new_default_line + '\n')
                        grub_default_found = True
                    else:
                        tmp_file.write(line)
                
                # 如果原来没有GRUB_DEFAULT，则添加
                if not grub_default_found:
                    tmp_file.write(new_default_line + '\n')
                
                tmp_path = tmp_file.name
            
            try:
                # 安全的文件替换
                if os.geteuid() != 0:
                    # 尝试使用 pkexec 进行替换
                    subprocess.run(['pkexec', 'mv', tmp_path, self.GRUB_DEFAULT_PATH], check=True)
                else:
                    shutil.move(tmp_path, self.GRUB_DEFAULT_PATH)
            except Exception as e:
                os.unlink(tmp_path)  # 确保清理临时文件
                raise RuntimeError(f"更新GRUB配置失败: {str(e)}")
        
        except Exception as e:
            raise RuntimeError(f"更新GRUB配置失败: {str(e)}")

    def _is_valid_grub_default(self, line):
        """验证GRUB默认配置行是否有效"""
        # 简单验证GRUB_DEFAULT格式
        pattern = r'^GRUB_DEFAULT="[^"]*"$'
        return re.match(pattern, line) is not None

    def _set_next_boot_entry(self, menu_path):
        """设置下次启动条目"""
        try:
            commands_to_try = [
                ['grub-reboot', menu_path],
                ['/usr/sbin/grub-reboot', menu_path]
            ]
            
            success = False
            if os.geteuid() != 0:
                for cmd in commands_to_try:
                    try:
                        subprocess.run(['pkexec'] + cmd, check=True)
                        success = True
                        break
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            subprocess.run(['sudo'] + cmd, check=True)
                            success = True
                            break
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            continue
            else:
                for cmd in commands_to_try:
                    try:
                        subprocess.run(cmd, check=True)
                        success = True
                        break
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        continue
            
            if not success:
                raise RuntimeError("无法设置下次启动条目")
                
        except Exception as e:
            raise RuntimeError(f"设置下次启动条目失败: {str(e)}")

    def _clean_grub_entry_id(self, entry_id):
        """
        清理GRUB条目ID，确保它是一个有效的标识符
        """
        # 如果entry_id是复杂字符串（包含引号、特殊字符等），尝试提取简单版本
        if isinstance(entry_id, str):
            # 如果包含逗号，可能是完整菜单项，提取第一部分
            if ',' in entry_id:
                entry_id = entry_id.split(',')[0].strip()
            
            # 移除可能的引号
            entry_id = entry_id.strip('"\'')
            
            # 如果是数字，直接返回数字（GRUB索引方式）
            if entry_id.isdigit():
                return entry_id
            
            # 如果太长或者包含特殊字符，考虑使用索引方式
            if len(entry_id) > 100 or any(c in entry_id for c in ['--class', '$menuentry_id_option']):
                # 返回简单的索引方式
                return "0"  # 默认启动第一个条目
        
        return entry_id

    def update_grub_config(self):
        """更新GRUB配置"""
        try:
            # 首先尝试使用 update-grub (Debian/Ubuntu 系统)
            commands_to_try = [
                ['update-grub'],
                ['grub-mkconfig', '-o', self.grub_cfg_path],
                ['/usr/sbin/grub-mkconfig', '-o', self.grub_cfg_path]
            ]
            
            if os.geteuid() != 0:
                # 需要提权的情况
                for cmd in commands_to_try:
                    try:
                        subprocess.run(['pkexec'] + cmd, check=True)
                        return True
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        try:
                            subprocess.run(['sudo'] + cmd, check=True)
                            return True
                        except (subprocess.CalledProcessError, FileNotFoundError):
                            continue  # 尝试下一个命令
                raise PermissionError("无法更新GRUB配置")
            else:
                # 已经是root权限
                for cmd in commands_to_try:
                    try:
                        subprocess.run(cmd, check=True)
                        return True
                    except (subprocess.CalledProcessError, FileNotFoundError):
                        continue  # 尝试下一个命令
                raise RuntimeError("无法更新GRUB配置")
                
        except Exception as e:
            print(f"更新GRUB配置失败: {e}")
            raise RuntimeError(f"无法更新GRUB配置: {e}")
    

class LogWindow(QDialog):
    """日志窗口类"""
    def __init__(self, parent, title="操作日志"):
        super().__init__(parent)
        self.parent = parent
        self.setWindowTitle(title)
        self.resize(600, 400)
        self.setModal(False)
        
        # 居中显示
        if parent:
            parent_geo = parent.geometry()
            self.move(
                parent_geo.x() + (parent_geo.width() - self.width()) // 2,
                parent_geo.y() + (parent_geo.height() - self.height()) // 2
            )
        
        self.setup_ui()
        
    def setup_ui(self):
        """设置界面"""
        layout = QVBoxLayout()
        
        # 创建文本框
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        layout.addWidget(self.log_text)
        
        # 创建按钮框架
        button_layout = QHBoxLayout()
        
        # 清除按钮
        self.clear_button = QPushButton("清除日志")
        self.clear_button.clicked.connect(self.clear_log)
        button_layout.addWidget(self.clear_button)
        
        # 关闭按钮
        self.close_button = QPushButton("关闭")
        self.close_button.clicked.connect(self.close)
        button_layout.addStretch()
        button_layout.addWidget(self.close_button)
        
        layout.addLayout(button_layout)
        self.setLayout(layout)
        
    def add_log(self, message):
        """添加日志信息"""
        self.log_text.append(message)
        self.log_text.verticalScrollBar().setValue(self.log_text.verticalScrollBar().maximum())
        QApplication.processEvents()  # 确保实时更新
        
    def clear_log(self):
        """清除日志"""
        self.log_text.clear()


class KernelManagementGUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Linux 内核管理工具")
        self.setGeometry(100, 100, 900, 700)
        self.setMinimumSize(800, 600)
        
        # 设置窗口图标
        self.setup_icon()
        
        # 设置窗口类名（与 .desktop 文件中的 StartupWMClass 匹配）
        # PyQt5 中没有 setWindowClassName 方法，使用 setWindowClass 或者通过其他方式设置
        # 方法1: 使用 setProperty 设置窗口属性
        self.setProperty("windowClass", "KernelManagementGUI")
        
        # 方法2: 通过设置窗口标志和属性来确保正确识别
        # 这种方法更符合 PyQt5 的规范
        # self.setWindowFlags(self.windowFlags() | Qt.WindowDoesNotAcceptFocus)
        
        self.boot_manager = BootManager(self)  # 传递自身实例给 BootManager
        
        # 创建主窗口部件
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        
        # 创建主布局
        self.main_layout = QVBoxLayout(self.central_widget)
        
        # 创建主内容
        self.create_main_content()
        
        # 初始化数据
        self._delayed_refresh()

    def showEvent(self, event):
        """窗口显示事件，确保搜索框能获得焦点"""
        super().showEvent(event)
        # 延迟设置焦点，确保界面完全加载
        QTimer.singleShot(100, self.focus_search_box)
        
    def focus_search_box(self):
        """为搜索框设置焦点"""
        self.global_search_edit.setFocus()
        self.global_search_edit.activateWindow()

    def setup_icon(self):
        """设置应用程序图标"""
        try:
            # 尝试设置图标（如果图标文件存在）
            icon_path = "/usr/share/icons/hicolor/48x48/apps/kernel-management.png"
            if os.path.exists(icon_path):
                self.setWindowIcon(QIcon(icon_path))
        except Exception:
            pass

    def create_main_content(self):
        """创建主内容区域"""
        # 搜索框 
        search_layout = QHBoxLayout()
        search_layout.addWidget(QLabel("搜索内核:"))
        
        self.global_search_edit = QLineEdit()
        self.global_search_edit.setFocusPolicy(Qt.StrongFocus)  # 添加这行
        self.global_search_edit.setPlaceholderText("输入内核版本或任意字符进行搜索")  # 添加提示文本
        self.global_search_edit.textChanged.connect(self.on_global_search)
        search_layout.addWidget(self.global_search_edit)
        
        clear_btn = QPushButton("清除")
        clear_btn.clicked.connect(self.clear_global_search)
        search_layout.addWidget(clear_btn)
        
        self.main_layout.addLayout(search_layout)
        
        # 安装/移除按钮框架
        button_layout = QHBoxLayout()
        
        # 安装内核按钮
        self.install_btn = QPushButton("安装选中内核")
        self.install_btn.setStyleSheet("color: green")
        self.install_btn.clicked.connect(self.install_selected_kernel)
        button_layout.addWidget(self.install_btn)
        
        # 移除内核按钮
        self.remove_btn = QPushButton("移除选中内核")
        self.remove_btn.setStyleSheet("color: red")
        self.remove_btn.clicked.connect(self.remove_selected_kernel)
        button_layout.addWidget(self.remove_btn)
        
        # 刷新按钮
        refresh_btn = QPushButton("刷新列表")
        refresh_btn.setStyleSheet("color: blue")
        refresh_btn.clicked.connect(self.refresh_all)
        button_layout.addWidget(refresh_btn)
        
        button_layout.addStretch()
        self.main_layout.addLayout(button_layout)
        
        # 内核列表框
        self.install_listbox = QListWidget()
        self.install_listbox.setSelectionMode(QListWidget.SingleSelection)
        self.main_layout.addWidget(self.install_listbox)
        
        # 图例框架
        legend_layout = QHBoxLayout()
        
        installed_indicator = QLabel("✓ 已安装")
        installed_indicator.setStyleSheet("color: green")
        legend_layout.addWidget(installed_indicator)
        
        not_installed_indicator = QLabel("○ 未安装")
        not_installed_indicator.setStyleSheet("color: gray")
        legend_layout.addWidget(not_installed_indicator)
        
        tool_installed_indicator = QLabel("[工具安装]")
        tool_installed_indicator.setStyleSheet("color: blue")
        legend_layout.addWidget(tool_installed_indicator)
        
        current_indicator = QLabel("[当前内核]")
        current_indicator.setStyleSheet("color: purple")
        legend_layout.addWidget(current_indicator)
        
        default_indicator = QLabel("[默认启动]")
        default_indicator.setStyleSheet("color: red")
        legend_layout.addWidget(default_indicator)
        
        next_indicator = QLabel("[下次启动]")
        next_indicator.setStyleSheet("color: orange")
        legend_layout.addWidget(next_indicator)
        
        legend_layout.addStretch()
        self.main_layout.addLayout(legend_layout)
        
        # 添加设置默认启动内核按钮
        set_default_layout = QHBoxLayout()
        set_default_layout.addStretch()
        
        # 临时设置默认内核按钮 (使用推荐方式)
        set_temp_default_btn = QPushButton("设为下次启动内核")
        set_temp_default_btn.setStyleSheet("color: orange")
        set_temp_default_btn.clicked.connect(lambda: self.set_default_kernel_with_recommended_method(permanent=False))
        set_default_layout.addWidget(set_temp_default_btn)
        
        # 永久设置默认内核按钮 (使用推荐方式)
        set_perm_default_btn = QPushButton("⚠️设为默认启动内核⚠️")
        set_perm_default_btn.setStyleSheet("color: red")
        set_perm_default_btn.clicked.connect(lambda: self.set_default_kernel_with_recommended_method(permanent=True))
        set_default_layout.addWidget(set_perm_default_btn)
        
        self.main_layout.addLayout(set_default_layout)
        
        # 添加全局说明文本
        info_text = """
    ⚠️ 警告：内核管理操作具有高风险-使用本软件表示您已完全了解并同意所有风险。 ⚠️
    - 在使用本工具前，请务必了解以下事项：
    - 1. 安装或移除内核可能影响系统稳定性
    - 2. 操作前请确保已备份重要数据
    - 3. 建议在有经验的用户指导下操作
    - 4. 软件作者对使用本软件产生的任何损失不承担任何责任
    - 请务必阅读以上注意事项，并请务必保证您完全了解内核管理操作所带来的影响再继续使用该工具！
        """
        self.global_info_label = QLabel(info_text)
        self.global_info_label.setWordWrap(True)
        self.global_info_label.setAlignment(Qt.AlignLeft)
        self.main_layout.addWidget(self.global_info_label)
        
        # 添加状态标签
        self.install_status_label = QLabel("就绪")
        self.install_status_label.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.install_status_label.setAlignment(Qt.AlignLeft)
        self.main_layout.addWidget(self.install_status_label)
        
        # 底部作者信息
        version = KM_VERSION
        author_text = f"作者: xiyidaiwa < a343025902@qq.com >\n" \
                     f"网址: https://gitee.com/gys1987/simple-management-of-the-kernel\n" \
                     f"版本: {version}"
        
        self.author_label = QLabel(author_text)
        self.author_label.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.author_label.setAlignment(Qt.AlignCenter)
        self.main_layout.addWidget(self.author_label)

    def _delayed_refresh(self):
        """延迟刷新以确保界面完全初始化"""
        try:
            self.refresh_all()
        except Exception as e:
            self.install_status_label.setText(f"初始化失败: {str(e)}")

    def get_all_available_kernels(self):
        """获取所有可用的内核包"""
        try:
            # 使用包管理器检测
            package_manager = PackageManager()
            
            if package_manager.package_manager == 'apt':
                result = subprocess.run(['apt-cache', 'search', '^linux-image'], 
                                    capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.strip():
                        kernel_name = line.split()[0]
                        # 过滤掉包含'extra'和'dbg'的内核
                        if (kernel_name.startswith('linux-image-') and 
                            'extra' not in kernel_name and 
                            'dbg' not in kernel_name):
                            kernels.append(kernel_name)
                return kernels
            else:
                self.show_message("错误", f"不支持的包管理器: {package_manager.package_manager}", 'error')
                return []
        except subprocess.CalledProcessError:
            self.show_message("错误", "无法获取可用内核列表", 'error')
            return []
        
    def get_installed_kernels(self):
        """列出所有已安装的内核"""
        try:
            # 使用包管理器检测
            package_manager = PackageManager()
            
            if package_manager.package_manager == 'apt':
                result = subprocess.run(['dpkg', '--list', 'linux-image-*'], 
                                      capture_output=True, text=True, check=True)
                kernels = []
                for line in result.stdout.split('\n'):
                    if line.startswith('ii'):
                        kernel_name = line.split()[1]
                        if kernel_name.startswith('linux-image-') and 'extra' not in kernel_name:
                            kernels.append(kernel_name)
                return kernels
            else:
                self.show_message("错误", f"不支持的包管理器: {package_manager.package_manager}", 'error')
                return []
        except subprocess.CalledProcessError:
            self.show_message("错误", "无法获取已安装内核列表", 'error')
            return []
    
    def get_current_kernel(self):
        """获取当前正在使用的内核"""
        try:
            result = subprocess.run(['uname', '-r'], 
                                  capture_output=True, text=True, check=True)
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return None

    def refresh_install(self):
        """刷新可用内核列表，在其中标注已安装的内核"""
        try:
            self.install_status_label.setText("正在获取可用内核...")
            QApplication.processEvents()
            
            self.install_listbox.clear()
            available_kernels = self.get_all_available_kernels()
            installed_kernels = self.get_installed_kernels()
            current_kernel = self.get_current_kernel()
            
            # 提取已安装内核的版本号用于比较
            installed_versions = {}
            for kernel in installed_kernels:
                # 根据不同包管理器提取版本号
                if kernel.startswith('linux-image-'):
                    version = kernel.replace('linux-image-', '')
                else:
                    version = kernel.replace('linux-', '')
                installed_versions[version] = kernel  # 保存完整内核名和版本的映射
            
            # 加载安装记录
            install_records = InstallRecordManager.load_records()
            
            # 加载默认启动和下次启动内核记录
            default_boot_kernel = DefaultBootManager.load_default_boot()
            next_boot_kernel = DefaultBootManager.load_next_boot()
            
            # 分别存储已安装和未安装的内核
            installed_kernels_list = []
            available_kernels_list = []
            
            # 处理已安装的内核
            for kernel in installed_kernels:
                # 根据不同包管理器提取版本号
                if kernel.startswith('linux-image-'):
                    version = kernel.replace('linux-image-', '')
                else:
                    version = kernel.replace('linux-', '')
                
                # 检查各种标记
                is_current = False
                if current_kernel and (
                    current_kernel == version or 
                    version in current_kernel or 
                    current_kernel in version):
                    is_current = True
                
                # 检查是否通过本工具安装
                is_tool_installed = version in install_records
                
                # 检查是否为默认启动内核 (使用更宽松的匹配)
                is_default = False
                if default_boot_kernel and (
                    default_boot_kernel == version or 
                    version in default_boot_kernel or 
                    default_boot_kernel in version):
                    is_default = True
                
                # 检查是否为下次启动内核 (使用更宽松的匹配)
                is_next = False
                if next_boot_kernel and (
                    next_boot_kernel == version or 
                    version in next_boot_kernel or 
                    next_boot_kernel in version):
                    is_next = True
                
                # 构建显示文本 - 按照指定顺序显示标记
                display_text = f"✓ {kernel}"
                tags = []
                
                if is_current:
                    tags.append("当前内核")
                
                if is_next:
                    tags.append("下次启动")
                
                if is_default:
                    tags.append("默认启动")
                
                if is_tool_installed:
                    tags.append("工具安装")
                
                # 按照指定顺序添加标记
                if tags:
                    display_text += " [" + "][".join(tags) + "]"
                
                installed_kernels_list.append((display_text, "green"))
            
            # 处理未安装的内核
            for kernel in available_kernels:
                # 检查是否已安装（避免重复显示）
                is_installed = False
                if kernel.startswith('linux-image-'):
                    version = kernel.replace('linux-image-', '')
                else:
                    version = kernel.replace('linux-', '')
                
                if version in installed_versions:
                    is_installed = True
                
                if not is_installed:
                    display_text = f"○ {kernel}"
                    available_kernels_list.append((display_text, "gray"))
            
            # 保存所有项目以供搜索使用
            self._all_install_items = installed_kernels_list + available_kernels_list
            
            # 先显示已安装的内核
            for display_text, color in installed_kernels_list:
                item = QListWidgetItem(display_text)
                if color == "green":
                    item.setForeground(QColor("green"))
                elif color == "gray":
                    item.setForeground(QColor("gray"))
                self.install_listbox.addItem(item)
                
            # 再显示未安装的内核
            for display_text, color in available_kernels_list:
                item = QListWidgetItem(display_text)
                if color == "green":
                    item.setForeground(QColor("green"))
                elif color == "gray":
                    item.setForeground(QColor("gray"))
                self.install_listbox.addItem(item)
            
            # 如果有搜索内容，应用搜索过滤
            search_term = self.global_search_edit.text().lower()
            if search_term:
                self.on_global_search()
            
            # 数据刷新完成后，更新状态栏文本
            self.install_status_label.setText(f"就绪 (可用内核: {len(available_kernels)}, 已安装内核: {len(installed_kernels)})")
            
        except Exception as e:
            self.install_status_label.setText(f"刷新失败: {str(e)}")
            import traceback
            traceback.print_exc()

    def on_global_search(self):
        """处理全局搜索输入变化 - 增强版"""
        search_term = self.global_search_edit.text().lower().strip()
        
        if not hasattr(self, '_all_install_items'):
            return
            
        # 保存当前选中项
        selected_items = self.install_listbox.selectedItems()
        selected_text = selected_items[0].text() if selected_items else None
            
        self.install_listbox.clear()
        
        if not search_term:
            # 如果搜索词为空，显示所有项目
            for item_text, color in self._all_install_items:
                item = QListWidgetItem(item_text)
                if color == "green":
                    item.setForeground(QColor("green"))
                elif color == "gray":
                    item.setForeground(QColor("gray"))
                self.install_listbox.addItem(item)
                
                # 恢复选中项
                if selected_text and item_text == selected_text:
                    item.setSelected(True)
            return
        
        # 支持多种匹配方式
        for item_text, color in self._all_install_items:
            # 精确匹配
            if search_term in item_text.lower():
                item = QListWidgetItem(item_text)
                if color == "green":
                    item.setForeground(QColor("green"))
                elif color == "gray":
                    item.setForeground(QColor("gray"))
                self.install_listbox.addItem(item)
                continue
                
            # 版本号匹配（提取版本号进行匹配）
            version_match = re.search(r'(\d+\.\d+\.\d+[-\w]*)', item_text)
            if version_match and search_term in version_match.group(1):
                item = QListWidgetItem(item_text)
                if color == "green":
                    item.setForeground(QColor("green"))
                elif color == "gray":
                    item.setForeground(QColor("gray"))
                self.install_listbox.addItem(item)

    def clear_global_search(self):
        """清除全局搜索框"""
        self.global_search_edit.clear()
        
        if hasattr(self, '_all_install_items'):
            self.install_listbox.clear()
            for item_text, color in self._all_install_items:
                item = QListWidgetItem(item_text)
                if color == "green":
                    item.setForeground(QColor("green"))
                elif color == "gray":
                    item.setForeground(QColor("gray"))
                self.install_listbox.addItem(item)

    def install_selected_kernel(self):
        """安装选中的内核"""
        items = self.install_listbox.selectedItems()
        if not items:
            self.show_message("提示", "请先选择一个内核", 'warning')
            return
            
        item = items[0]
        
        # 检查是否已安装
        if item.text().startswith("✓"):
            self.show_message("提示", "该内核已安装，无法重复安装", 'warning')
            return
            
        # 提取内核名称（去除标记符号）
        kernel_name = item.text().replace("✓ ", "").replace("○ ", "").split(" ")[0]
        
        # 确认安装
        if not self.show_message("确认安装", f"确定要安装内核 {kernel_name} 吗？", 'question'):
            return
            
        # 创建日志窗口
        log_window = LogWindow(self, f"安装内核 {kernel_name} 的日志")
        log_window.add_log(f"开始安装内核: {kernel_name}")
        log_window.show()
        
        self.install_status_label.setText(f"正在安装 {kernel_name}...")
        QApplication.processEvents()
        
        try:
            # 使用包管理器安装
            package_manager = PackageManager()
            log_window.add_log(f"检测到的包管理器: {package_manager.package_manager}")
            
            # 获取相关的包名
            base_version = kernel_name.replace('linux-image-', '').replace('linux-', '')
            package_names = package_manager.get_package_names(base_version, 'install')
            log_window.add_log(f"将要安装的包: {', '.join(package_names)}")
            
            # 安装包
            installed_packages = package_manager.install_packages(package_names, log_window)
                
            # 记录安装信息
            InstallRecordManager.add_record(base_version, installed_packages)
            log_window.add_log(f"内核 {kernel_name} 安装完成，已记录安装信息")
            self.show_message("成功", f"内核 {kernel_name} 安装完成", 'info')
            self.refresh_install()
            
        except Exception as e:
            log_window.add_log(f"安装内核失败: {str(e)}")
            self.show_message("错误", f"安装内核失败: {str(e)}", 'error')
            self.install_status_label.setText("安装失败")
            return False
        else:
            self.install_status_label.setText("安装完成")
            return True

    def remove_selected_kernel(self):
        """移除选中的内核"""
        items = self.install_listbox.selectedItems()
        if not items:
            self.show_message("提示", "请先选择一个内核", 'warning')
            return
            
        item = items[0]
        # 检查是否已安装
        if not item.text().startswith("✓"):
            self.show_message("提示", "只能移除已安装的内核", 'warning')
            return
            
        # 检查是否有保护标记
        item_text = item.text()
        if "当前内核" in item_text or "下次启动" in item_text or "默认启动" in item_text:
            self.show_message("提示", "无法移除当前内核、下次启动内核或默认启动内核", 'warning')
            return
            
        # 提取内核名称（去除标记符号）
        kernel_name = item_text.replace("✓ ", "").split(" ")[0]
        
        # 双重保障：检查是否为当前正在运行的内核
        current_kernel = self.get_current_kernel()
        # 根据不同包管理器提取版本号进行比较
        if kernel_name.startswith('linux-image-'):
            kernel_version = kernel_name.replace('linux-image-', '')
        else:
            kernel_version = kernel_name.replace('linux-', '')
            
        # 检查是否与当前运行内核匹配（更宽松的匹配）
        if current_kernel and (
            current_kernel == kernel_version or 
            kernel_version in current_kernel or 
            current_kernel in kernel_version):
            self.show_message("提示", "无法移除当前正在运行的内核", 'warning')
            return
        
        # 确认移除
        if not self.show_message("确认移除", f"确定要移除内核 {kernel_name} 吗？", 'question'):
            return
            
        # 创建日志窗口
        log_window = LogWindow(self, f"移除内核 {kernel_name} 的日志")
        log_window.add_log(f"开始移除内核: {kernel_name}")
        log_window.show()
        
        self.install_status_label.setText(f"正在移除 {kernel_name}...")
        QApplication.processEvents()
        
        try:
            # 使用包管理器移除
            package_manager = PackageManager()
            log_window.add_log(f"检测到的包管理器: {package_manager.package_manager}")
            
            # 获取相关的包名
            base_version = kernel_name.replace('linux-image-', '').replace('linux-', '')
            package_names = package_manager.get_package_names(base_version, 'remove')
            log_window.add_log(f"将要移除的包: {package_names}")
            
            # 移除包
            package_manager.remove_packages(package_names, log_window)
            
            # 移除安装记录
            InstallRecordManager.remove_record(base_version)
            log_window.add_log(f"内核 {package_names} 移除完成，已清除安装记录")
            self.show_message("成功", f"内核 {package_names} 移除完成", 'info')
            self.refresh_install()
            
        except Exception as e:
            log_window.add_log(f"移除内核失败: {str(e)}")
            self.show_message("错误", f"移除内核失败: {str(e)}", 'error')
            self.install_status_label.setText("移除失败")
            return False
        else:
            self.install_status_label.setText("移除完成")
            return True

    def set_default_kernel_with_recommended_method(self, permanent=True):
        """
        使用GRUB推荐方式设置默认启动内核
        根据GRUB版本使用不同的格式:
        - GRUB < 2.00: "Advanced options for Ubuntu>Ubuntu, with Linux X.X.X-generic"
        - GRUB >= 2.00: "gnulinux-advanced-UUID>gnulinux-X.X.X-generic-advanced-UUID"
        """
        result = self.boot_manager.set_default_kernel_with_recommended_method(permanent=permanent)
        if result:
            self.handle_set_kernel_result(result)
            self.refresh_install()  # 刷新显示以更新标记

    def handle_set_kernel_result(self, result):
        if result["success"]:
            self.show_message(result["title"], result["message"], 'info')
        else:
            self.show_message(result["title"], result["message"], 'error')

    def refresh_all(self):
        """刷新所有数据"""
        try:
            self.refresh_install()
        except Exception as e:
            self.install_status_label.setText(f"刷新失败: {str(e)}")

    def show_message(self, title, message, msg_type='info'):
        """显示消息对话框"""
        if msg_type == 'error':
            return QMessageBox.critical(self, title, message)
        elif msg_type == 'warning':
            return QMessageBox.warning(self, title, message)
        elif msg_type == 'question':
            return QMessageBox.question(self, title, message) == QMessageBox.Yes
        else:
            return QMessageBox.information(self, title, message)

def main():
    # 禁用 accessibility bus 警告
    os.environ['NO_AT_BRIDGE'] = '1'
    
    # 设置主题相关环境变量
    if 'QT_QPA_PLATFORMTHEME' not in os.environ:
        os.environ['QT_QPA_PLATFORMTHEME'] = 'gtk'
    
    app = QApplication(sys.argv)
    # 设置应用程序名称，这会影响 WM_CLASS
    app.setApplicationName('KernelManagementGUI')
    app.setApplicationDisplayName('Linux 内核管理工具')
    
    # 检测并应用系统主题
    setup_system_theme(app)
    
    window = KernelManagementGUI()
    
    # 创建权限提醒对话框
    warning_dialog = None
    if os.geteuid() != 0:
        warning_dialog = QMessageBox(window)
        warning_dialog.setIcon(QMessageBox.Warning)
        warning_dialog.setWindowTitle("权限提醒")
        warning_dialog.setText("某些操作可能需要root权限")
        warning_dialog.setStandardButtons(QMessageBox.Ok)
        
        # 设置定时器，5秒后自动关闭对话框
        def close_warning_dialog():
            if warning_dialog and warning_dialog.isVisible():
                warning_dialog.close()
                
        timer = QTimer()
        timer.timeout.connect(close_warning_dialog)
        timer.setSingleShot(True)
        timer.start(5000)  # 5秒后触发
        
        # 显示对话框（非模态）
        warning_dialog.setModal(False)
        warning_dialog.show()
    
    window.show()
    sys.exit(app.exec_())

def setup_system_theme(app):
    """设置系统主题"""
    try:
        # 检查是否有可用的主题
        available_styles = QStyleFactory.keys()
        
        # 尝试获取系统GTK主题设置
        try:
            # 检查是否在GNOME环境中
            desktop = os.environ.get('XDG_CURRENT_DESKTOP', '').lower()
            if 'gnome' in desktop:
                # GNOME环境下使用默认主题
                pass
            elif 'kde' in desktop:
                # KDE环境下使用Fusion主题
                if 'Fusion' in available_styles:
                    app.setStyle(QStyleFactory.create('Fusion'))
            else:
                # 其他环境尝试使用GTK主题
                if 'GTK+' in available_styles:
                    app.setStyle(QStyleFactory.create('GTK+'))
        except:
            # fallback到默认处理
            pass
            
    except Exception as e:
        print(f"设置主题时出错: {e}")

if __name__ == "__main__":
    main()